package org.ainlolcat;

import java.util.HashMap;

/**
 * @author ainlolcat
 * Date: 11/13/11
 */
public class Variable {
    public final static int TYPE_INTEGER = 10;
    public final static int TYPE_DOUBLE = 11;
    public final static int TYPE_STRING = 12;
    public final static int TYPE_BOOLEAN = 13;

    private String name;
    private Object value;
    private Integer type;

    public Variable(Object value, Integer type){
        this.type = type;
        setValue(value);
    }

    public Variable(String name, Object value, Integer type) {
        this.name = name;
        this.type = type;
        setValue(value);
    }

    public Variable(boolean value){
        this.value = value;
        type = TYPE_BOOLEAN;
    }

    public Variable(double value){
        this.value = value;
        type = TYPE_DOUBLE;
    }

    public Variable(int value){
        this.value = value;
        type = TYPE_INTEGER;
    }

    public Variable(String value){
        this.value = value;
        type = TYPE_STRING;
    }

    public String getName(){
        return name;
    }

    public boolean getBooleanValue(){
        return (Boolean)value;
    }

    public String getStringValue(){
        return value!=null ? value.toString() : null;
    }

    public Integer getIntegerValue(){
        if (type == TYPE_INTEGER){
            return (Integer) value;
        }
        throw new RuntimeException("Wrong type for integer " + getTypeAsString(type));
    }

    public Double getDoubleValue(){
        if (value == null) return null;
        if (type == TYPE_DOUBLE){
            return (Double) value;
        } else if (type == TYPE_INTEGER){
            return Double.parseDouble(value.toString());
        }
        throw new RuntimeException("Wrong type for double " + getTypeAsString(type));
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        if (value == null) {
            this.value = null;
            return;
        }
        switch (type){
            case TYPE_INTEGER :{
                setIntegerValue(value);
                break;
            }
            case TYPE_DOUBLE :{
                setDoubleValue(value);
                break;
            }
            case TYPE_BOOLEAN:{
                setBooleanValue(value);
                break;
            }
            default:
                this.value = value.toString();
        }
    }

    private void setIntegerValue(Object object){
        if (object instanceof Integer)
            value = object;
        else
            value = Integer.parseInt(object.toString());
    }

    private void setDoubleValue(Object object){
        if (object instanceof Double)
            value = object;
        else
            value = Double.parseDouble(object.toString());
    }

    private void setBooleanValue(Object object){
        if (object instanceof Boolean)
            value = object;
        else
            value = Boolean.parseBoolean(object.toString());
    }

    public Integer getType() {
        return type;
    }

    public static String getTypeAsString(int type){
        switch (type){
            case TYPE_INTEGER :{
                return "int";
            }
            case TYPE_DOUBLE :{
                return "double";
            }
            case TYPE_BOOLEAN:{
                return "boolean";
            }
            case TYPE_STRING:{
                return "string";
            }
            default:
                throw new IllegalArgumentException();
        }
    }

    static HashMap<String, Integer> types = new HashMap<String, Integer>();

    static {
        types.put("int", TYPE_INTEGER);
        types.put("double", TYPE_DOUBLE);
        types.put("string", TYPE_STRING);
        types.put("boolean", TYPE_BOOLEAN);
    }

    public static int resolveType(String type){
        return types.get(type);
    }
}
